package sketches;

import controlP5.ControlP5;
import geomerative.RCommand;
import geomerative.RFont;
import geomerative.RG;
import geomerative.RGroup;
import geomerative.RPoint;
import geomerative.RShape;
import processing.core.PApplet;
import processing.core.PGraphics;
import processing.core.PShape;

public class caligraft_02 extends PApplet{

	RGroup grupo;
	Particle particula;
	float toldist;
	float maxvel;
	float maxalph;

	RFont f;
	
	RShape myShape; 
	
	ControlP5 controlP5;

	//------------------------ Runtime properties ----------------------------------
	// Save each frame
	boolean SAVEVIDEO = true;
	boolean SAVEFRAME = false;
	boolean APPLICATION = true;

	String DEFAULTAPPLETRENDERER = JAVA2D;
	int DEFAULTAPPLETWIDTH = 680;
	int DEFAULTAPPLETHEIGHT = 480;

	String DEFAULTAPPLICRENDERER = OPENGL;
	int DEFAULTAPPLICWIDTH = 800;
	int DEFAULTAPPLICHEIGHT = 600;
	//------------------------------------------------------------------------------

	//------------------------ Drawing properties ----------------------------------
	// Text to be drawn
	String STRNG = "Caligraft";

	// Font to be used
	String FONT = "FreeSans.ttf"; //LidoSTF.ttf

	// Margin from the borders
	float MARGIN = 50;
	//------------------------------------------------------------------------------


	//------------------------- Drawer properties ----------------------------------
	// The coefficient of the velocity of getting to a desired point
	float MINNERVE = 0.002f;
	float MAXNERVE = 0.005f;

	// The average of mininertia and maxinertia must be under one to have good results
	float MININERTIA = 0.7f;
	float MAXINERTIA = 1.2f;

	// Coefficient that handles the error of the drawing: 0 for lowest error
	float DRWERRCOEFF = 1.0009f;

	// Coefficient that handles the variation of amount of ink for the drawing 
	float INKERRCOEFF = 0.5f;

	// Coefficient that handles the amount of ink for the drawing
	float INKCOEFF = 0.3f;

	// Coefficient of precision: 0 for lowest precision
	float PRECCOEFF = 0.8f;

	// Velocity of the drawing
	int VELOCIDAD = 128;
	//-----------------------------------------------------------------------------

	
	
	String newString = "";
	RPoint[] pointPaths;

	public void setup(){
		RG.init(this);
		  int w = DEFAULTAPPLICWIDTH, h = DEFAULTAPPLICHEIGHT;
		  String r = DEFAULTAPPLICRENDERER;
		  
		  if(!APPLICATION){
		    // Specify the widtha and height at runtime
//		    w = int(param("width"));
//		    h = int(param("height"));
//		    r = (String)param("renderer");
		  
		 
		    // (String) will return null if param("renderer") doesn't exist
		    if (r != OPENGL && r != P3D && r != JAVA2D && r != P2D) {
		      r = DEFAULTAPPLETRENDERER;
		    }
		    // int() will return 0 if param("width") doesn't exist
		    if (w <= 0) {
		      w = DEFAULTAPPLETWIDTH;
		    }
		    // int() will return 0 if param("height") doesn't exist
		    if (h <= 0) {
		      h = DEFAULTAPPLETHEIGHT;
		    }
		  }
		  
		  size(w,h,r);
		  frameRate(25);
		  try{
		    smooth();
		  }
		  catch(Exception e){
		  }

		  background(255);

		  f = new RFont(FONT,372,RFont.CENTER);
		  
		  RG.ignoreStyles(false);
		  RG.setPolygonizer(RG.ADAPTATIVE);
		  myShape = RG.loadShape("yoga.svg");
		  myShape.centerIn(g, 100, 1, 1);
		  pointPaths = myShape.getPoints();
		  
		  initialize();
		  
		  //setup controlP5
		  controlP5 = new ControlP5(this);
		  controlP5.addSlider("VELOCIDAD",0,255,128,5,5,100,10);
		  controlP5.addSlider("MINNERVE",0,0.01f,0.002f,5,20,100,10);
		  controlP5.addSlider("MAXNERVE",0,0.1f,0.005f,5,35,100,10);
		  controlP5.addSlider("MININERTIA",0,1.0f,0.7f,5,50,100,10);
		  controlP5.addSlider("MAXINERTIA",0,3.0f,1.2f,5,65,100,10);
		  
		  controlP5.addSlider("DRWERRCOEFF",0.001f,20f,0.08f,155,5,100,10); // Coefficient that handles the error of the drawing: 0 for lowest error
		  controlP5.addSlider("INKERRCOEFF",0,5f,0.5f,155,20,100,10);// Coefficient that handles the variation of amount of ink for the drawing 
		  controlP5.addSlider("INKCOEFF",0,1f,0.3f,155,35,100,10);// Coefficient that handles the amount of ink for the drawing
		  controlP5.addSlider("PRECCOEFF",0,1f,0.8f,155,50,100,10);// Coefficient of precision: 0 for lowest precision
		}
	
	public void draw(){
			
		  toldist = DRWERRCOEFF;// * (10F/(STRNG.length()+1));
		  maxvel = constrain(INKERRCOEFF,0.01f,INKERRCOEFF);
		  maxalph = 255 * constrain(INKCOEFF,0,1);
		  RCommand.setSegmentStep(1-constrain(PRECCOEFF,0,0.99f));
		  
		  pushMatrix();
		    translate(width/2, height/2);

		  for(int i=0;i<VELOCIDAD;i++){
			particula.update(pointPaths);
		    particula.draw(g);
		  }
		  popMatrix();

		  if(SAVEVIDEO) saveFrame("video-####.png");
		}

		void initialize(){
		  background(255);
		  
//		  toldist = (width/80F) * DRWERRCOEFF * (10F/(STRNG.length()+1));
//		  maxvel = (width/190F) * constrain(INKERRCOEFF,0.01f,INKERRCOEFF) * (10F/(STRNG.length()+1));
//		  maxalph = 255 * constrain(INKCOEFF,0,1);
//
//		  RCommand.setSegmentStep(1-constrain(PRECCOEFF,0,0.99f));
		  RCommand.setSegmentator(RCommand.UNIFORMSTEP);

		  particula = new Particle(g,0);
		}

		public void mouseDragged(){
		  float distToMouse = dist(particula.pos.x,particula.pos.y,mouseX-width/2,mouseY-height/2)*0.3f;
		  distToMouse = constrain(distToMouse,0.001f,distToMouse);
		  RPoint p = new RPoint(particula.pos);
		  p.add(new RPoint((mouseX-pmouseX)*random(0,0.5f)/distToMouse,(mouseY-pmouseY)*random(0,0.5f)/distToMouse));
		  particula.setPos(p);
		  particula.vel.add(new RPoint((mouseX-pmouseX)*random(0,0.5f)/distToMouse,(mouseY-pmouseY)*random(0,0.5f)/distToMouse));
		}

		public void keyReleased(){
		  //exit();
		  //saveFrame(STRNG+"-###.tga");
		  if(keyCode==ENTER){
		    STRNG = newString; 
		    newString = "";
		    initialize();
		  }else if(keyCode==BACKSPACE){
		    if(newString.length() !=0 ){
		      newString = newString.substring(0,newString.length()-1);
		    }
		  }else if(keyCode!=SHIFT){
		    newString += key;
		  }
		}
		
		
		public class Particle{
			  // Velocity
			  RPoint vel;

			  // Position
			  RPoint pos;
			  RPoint lastpos;

			  // Caracteristics
			  int col;
			  float sz;

			  // ID
			  int id;
		
		 // Constructor
		  public Particle(PGraphics gfx, int ident){
		    pos = new RPoint(random(-gfx.width/2,gfx.width/2), random(-gfx.height/2,gfx.height/2));
		    lastpos = new RPoint(pos);
		    vel = new RPoint(0, 0);

		    colorMode(HSB);
		    sz = random(2,3);

		    id = ident;
		  }

		// Updater of position, velocity and colour depending on a RGroup
		  public void update(RPoint[] thePoints){
			    lastpos = new RPoint(pos);
			    pos.add(vel);
//			    RPoint[] ps = grp.getPoints();
			    if(thePoints != null){
			      float distancia = dist(pos.x,pos.y,thePoints[id].x,thePoints[id].y);
			      if(distancia <= toldist){
			        id = (id + 1) % thePoints.length;
			        if(SAVEFRAME && id==0) saveFrame(STRNG+"frame-####.tga");
			      }

			      RPoint distPoint = new RPoint(thePoints[id]);
			      distPoint.sub(pos);

			      distPoint.scale(random(MINNERVE,MAXNERVE));
			      vel.scale(random(MININERTIA,MAXINERTIA));
			      vel.add(distPoint);

			      // Alpha and saturation in function of the velocity of the drawing
			      float velnorm = constrain(vel.norm(),0,maxvel);
			      float sat = abs(maxvel - velnorm)/maxvel*maxalph;
			      col = color(0,0,1,sat);
			    }
			  }

		  
		  public void setPos(RPoint newpos){
		    lastpos = new RPoint(pos);
		    pos = newpos;
		  }

		  // Drawing the particle
		  public void draw(PGraphics gfx){
		    stroke(col);
		    line(lastpos.x,lastpos.y,pos.x, pos.y);
		  }
		}
	
	static public void main(String[] args){
		PApplet.main(new String[]{caligraft_02.class.getName()});
	}
		
}
